1 Introduction

  • In this notebook, we present the first results of an analysis of green development paths of Nordic regions
  • It is based on patent data from 1990-2015 (PATSTAT, Autumn 2021 Edition)
  • Analysis is done on all Nordic NUTS 2 regions (fractionalized patent allocation by inventor location, DOCDB family level)
  • Industries are captured by NACE2 codes of patents according to the OECD IPC-NACE2 concordance table.
  • Green patents are identified using the Y02 tag in the CPC classification

1.1 Preprocessing

### general options
Sys.setenv(LANG = "en")
options("scipen" = 100, "digits" = 4) # override R's tendency to use scientific notation

### Clean workspace
rm(list=ls())
graphics.off()

### Load packages (maybe need to be installed first)
# Standard
library(tidyverse) # General DS toolkit
library(magrittr) # For advanced piping

# Databases
library(DBI) # GEneral R database interface
library(RPostgres) # PostgreSQL interface driver 
library(dbplyr) # for dplyr with databases

# networks
library(tidygraph)
library(ggraph)
library(ggrepel)

# GEoplot
library(giscoR)
library(sf)
## LOAD DATA

# Regular tables
data_appln <- read_rds('../temp/data_appln.rds')
data_pers_appln  <- read_rds('../temp/data_pers_appln.rds')
data_nace2 <- read_rds('../temp/data_nace2.rds')

#data_person <- read_rds('../temp/data_person.rds')
#data_docdb_fam_cpc <- read_rds('../temp/data_docdb_fam_cpc.rds')

# Regional specialization
region_RTA <- read_rds('../temp/region_RTA.rds') %>% 
  mutate(country = nuts %>% str_sub(1,2),
         nuts_period = paste(nuts, 'P', period)) 

region_tech <- read_rds('../temp/region_tech.rds') %>% 
  mutate(country = nuts %>% str_sub(1,2),
         nuts_period = paste(nuts, 'P', period)) 

# Technology space
g_tech <- read_rds('../temp/g_tech.rds')

# Lists
list_nace2 <- read_rds('../temp/list_nace2.rds')

# Applicants
region_applt_appln <- read_rds('../temp/tbl_region_applt_appln.rds') %>% select(-applt_seq_nr, -invt_seq_nr)
region_applt <- read_rds('../temp/tbl_region_applt.rds')
## Defining parameters
n_cutoff = 50
n_cutoff_green = 25
## SELECT FOCUS REGIONS
reg_in = '' # c('SE232', 'NO043', 'DK012')
n_regions = 5

# Restrict to top N regions
select_region <- region_tech %>%
  group_by(country, nuts) %>%
  summarise(n = sum(weight_frac, na.rm = TRUE),
            n_Y = sum(weight_frac * Y_tag, na.rm = TRUE)) %>%
  ungroup() %>%
  group_by(country) %>%
  arrange(nuts, desc(n_Y)) %>%
  mutate(index = 1:n()) %>%
  ungroup() %>%
  filter(index <= n_regions | nuts %in% reg_in) %>%
  distinct(nuts) %>%
  pull(nuts)
`summarise()` has grouped output by 'country'. You can override using the `.groups` argument.
rm(reg_in)
# Createdataframe with technology relatedness edgelist
tech_rel <- g_tech %E>%
  mutate(from_nace = .N()$name[from],
         to_nace = .N()$name[to]) %>%
  as_tibble() %>%
  mutate(from = from_nace %>% as.character(),
         to = to_nace %>% as.character()) %>%
  arrange(from, to) %>%
  select(from, to, weight)

tech_rel %<>%
  # Add opposite direction
  bind_rows(tech_rel %>% 
              rename(from_new = to, to_new = from) %>% 
              rename(from = from_new, to = to_new) %>%
              relocate(from, to)) %>%
  # Add self loops
  bind_rows(tech_rel %>%
              distinct(from) %>%
              mutate(to = from,
                     weight = 1)) %>%
  distinct(from, to, .keep_all = TRUE)
# Summarize Regions
region_RTA_agg <- region_RTA %>%
  group_by(country, nuts, period, nuts_period, Y_tag) %>%
  summarise(n_spec = rta_bin %>% sum(na.rm = TRUE),
            n_spec_count = (n_tech_region * rta_bin) %>% sum(na.rm = TRUE),
            HHI = sum((n_tech_region/sum(n_tech_region) * 100)^2) ) %>%
  ungroup() 
`summarise()` has grouped output by 'country', 'nuts', 'period', 'nuts_period'. You can override using the `.groups` argument.

2 Patent application development

  • In the following, a brief descriptive analysis of the development of green and non-green patent application in the Nordics
  • In addition, a breackdown of green patents by top green patenting reagions
# Dataframe with regions and technology fields
tech_dev <- region_RTA %>%
  select(country, period, nuts, nuts_period, nace_group, Y_tag, n_tech_region, rta, rta_bin) %>%
  arrange(country, nuts, nace_group, Y_tag, period) %>%
  group_by(country, nuts, nace_group, Y_tag) %>%
  mutate(n_tech_region_lag = lag(n_tech_region, 1),
         n_tech_region_delta = n_tech_region - n_tech_region_lag,
         pct_tech_region_delta = (n_tech_region - n_tech_region_lag) / ( n_tech_region_lag + 1),
         rta_lag = lag(rta, 1),
         rta_delta = rta - rta_lag,
         rta_bin_lag = lag(rta_bin, 1),
         rta_bin_delta = rta_bin - rta_bin_lag) %>%
  ungroup() %>%
  arrange(country, nuts, nace_group, Y_tag, period) 
data_appln %>%
  count(appln_filing_year, Y_tag) %>%
  ggplot(aes(x = appln_filing_year, y = n, col = Y_tag)) + 
  geom_line(key_glyph = "timeseries") +
  labs(title = 'Patent applications: Development',
       subtitle = 'All Nordic contries, by Y tag',
       x = 'Year',
       y = 'Number applications',
       col = 'Green')

3 Applicants

  • Applicants of patents filed by inventors in the Nordics
  • That can be domestic or foreign applicants
data_pers_appln %>%
  filter(nuts %in% select_region) %>%
  count(appln_filing_year, nuts, Y_tag, wt = weight_frac) %>%
  ggplot(aes(x = appln_filing_year, y = n, col = nuts)) + 
  geom_line(key_glyph = "timeseries") +
  facet_wrap(vars(Y_tag), scales = 'free') +
  labs(title = 'Patent applications: Development',
       subtitle = 'All Nordic contries',
       x = 'Year',
       y = 'Number applications, by region and Y tag',
       col = 'Nuts3')


region_applt_appln %<>%
  group_by(appln_id) %>%
  mutate(n_frac = 1 / n()) %>%
  ungroup() %>%
  left_join(region_applt %>% select(person_id, han_id, han_name, person_ctry_code, nuts), by = 'person_id') %>%
  left_join(data_appln %>% select(appln_id, docdb_family_id, appln_filing_year, period, Y_tag), by = 'appln_id') %>%
  left_join(data_nace2 %>% select(appln_id, nace_group) %>% group_by(appln_id) %>% mutate(nace_share = 1 / n()) %>% ungroup() %>% nest(nace = c(nace_group, nace_share)), by = 'appln_id') %>%
  drop_na()
# List main applicants
applt_stats <- region_applt_appln %>%
  group_by(han_id, han_name, person_ctry_code, nuts) %>%
  summarise(
    n_pat = sum(n_frac),
    n_Y = sum(n_frac * Y_tag),
    first_pat = min(appln_filing_year)
    ) %>%
  mutate(share_Y = n_Y / n_pat,
         age = 2016 - first_pat,
         incumbant = age >= 10 & n_pat >= n_cutoff) %>%
  ungroup() %>%
  arrange(desc(n_pat))
`summarise()` has grouped output by 'han_id', 'han_name', 'person_ctry_code'. You can override using the `.groups` argument.
applt_stats %>% head(200)
applt_stats %>% arrange(desc(n_Y)) %>% head(100)

4 Technology space general

  • We calculate the relatedness of industries by co-occurence pattern following Hidalgo & Hausmann (2007)
  • Revealed technological advantage (RTA) Is sepperatedly calculated for Y-tag and non-Y-tag patents.
# Share of incumbants by technology
region_techn_incumb <- region_applt_appln %>% 
  left_join(applt_stats %>% select(han_id, incumbant), by = 'han_id') %>%
  unnest(nace) %>%
  mutate(n_weight = n_frac * nace_share) %>%
  group_by(nuts, nace_group, period, Y_tag) %>%
  summarise(n = sum(n_weight),
            n_inc = sum(n_weight * incumbant)) %>%
  ungroup() %>%
  mutate(share_inc = n_inc / n)
`summarise()` has grouped output by 'nuts', 'nace_group', 'period'. You can override using the `.groups` argument.
set.seed(1337)
coords_tech <- g_tech %>% igraph::layout.fruchterman.reingold() %>% as_tibble()
colnames(coords_tech) <- c("x", "y")

5 Regional specialization (RTA) development

  • Comparison of specialization provides in period 1 and 2
g_tech %N>%
  mutate(nace_group_name = nace_group_name %>% str_trunc(50, side = 'right')) %>%
  ggraph(layout =  coords_tech) + 
  geom_edge_link(aes(width = weight, alpha = weight), colour = "grey") + 
  geom_node_point(aes(colour = nace_sec_name, size = dgr)) + 
  geom_node_text(aes(label = nace_group_name, size = dgr, filter = percent_rank(dgr) >= 0.75 ), repel = TRUE) +
  theme_void() +
  theme(legend.position="bottom") + 
  labs(title = 'Industry Space (all Nordics)',
       subtitle = 'Nodes = NACE 2 Industries. Edges: Relatedness')

p1 <- region_RTA_agg  %>%
  filter(nuts %in% select_region) %>%
  pivot_wider(names_from = Y_tag, values_from = c(n_spec, n_spec_count, HHI), values_fill = 0, names_prefix = 'Y_tag_') 

p2 <- p1 %>% 
  select(period, nuts, n_spec_Y_tag_FALSE, n_spec_Y_tag_TRUE) %>%
  pivot_wider(names_from = period, values_from = c(n_spec_Y_tag_FALSE, n_spec_Y_tag_TRUE))

6 Analysis for existing green paths:

p1 %>%
  ggplot(aes(x = n_spec_Y_tag_FALSE, y = n_spec_Y_tag_TRUE)) +
  geom_segment(data = p2, 
               aes(x = n_spec_Y_tag_FALSE_1,
                   y = n_spec_Y_tag_TRUE_1,
                   xend = n_spec_Y_tag_FALSE_2,
                   yend = n_spec_Y_tag_TRUE_2,
                   size = 0.75),
               alpha = 0.15,
               arrow = arrow(length = unit(0.5, "cm"), type = "closed"),
               show.legend = FALSE) +
  geom_point(aes(size = n_spec_count_Y_tag_TRUE, col = HHI_Y_tag_TRUE)) +
  geom_text_repel(aes(label = nuts), box.padding = 0.5, max.overlaps = Inf) +
  scale_color_gradient2(low = "skyblue", mid = 'yellow', high = "red", midpoint = 1) +
  scale_size(range = c(2, 10)) + 
  labs(title = 'Development of new regional specializations', 
       subtitle = 'By number of green and non green specializations in period 1 and 2',
       note = '',
       x = 'N non-green specializations',
       y = 'N green specializations',
       size = 'N green patents',
       col = 'HHI green patents') 


rm(p1, p2)
tech_rel_dev <- tech_rel %>% 
  select(from, to, weight) %>%
  left_join(tech_dev %>% distinct(nace_group, nuts), by = c('from' = 'nace_group')) %>%
  # filter for rta in period 1
  inner_join(tech_dev %>% filter(period == '1', rta_bin == 1) %>% select(nace_group, nuts, Y_tag), by = c('to' = 'nace_group', 'nuts')) %>%
  # filter for new green specialization in period 2
  semi_join(tech_dev %>% filter(period == '2', rta_bin == 1, rta_bin_delta == 1, Y_tag == TRUE), by = c('from' = 'nace_group', 'nuts')) %>%
  rename(nace_group = from, related_techn = to) 
p1 <- tech_rel_dev %>%
  group_by(nuts, nace_group, Y_tag) %>%
  summarise(rel_max = weight %>% max(),
            rel_sum = weight %>% sum(),
            rel_mean = weight %>% mean()) %>%
  ungroup() %>%
  #
  group_by(nuts, Y_tag) %>%
  summarise(rel = rel_max %>% mean()) %>%
  ungroup() %>%
  #
  pivot_wider(names_from = Y_tag, values_from = rel, names_prefix = 'Y_', values_fill = 0) %>%
  left_join(tech_dev %>% filter(Y_tag == TRUE, period == '2', rta_bin == 1) %>% select(nuts , n_tech_region) %>% count(nuts, wt = n_tech_region), by = c('nuts')) %>%
  mutate(country = nuts %>% str_sub(1,2)) 
`summarise()` has grouped output by 'nuts', 'nace_group'. You can override using the `.groups` argument.`summarise()` has grouped output by 'nuts'. You can override using the `.groups` argument.
x_mid <- mean(p1$Y_FALSE, na.rm = TRUE)
y_mid <- mean(p1$Y_TRUE, na.rm = TRUE)

p1 %>%
  filter(0.5 <= percent_rank(n)) %>%
  ggplot(aes(x = Y_FALSE, y = Y_TRUE, size = n)) +
  geom_vline(xintercept = x_mid, linetype = "dashed", color = 'grey') + 
  geom_hline(yintercept = y_mid, linetype = "dashed", color = 'grey') +
  geom_point(aes(col = country)) +
  geom_text_repel(aes(label = nuts), box.padding = 0.5, max.overlaps = Inf) +
  theme(legend.position="bottom") + 
    labs(title = 'New green specialization period 2', 
       subtitle = 'By nuts regions',
       note = 'Relatedness is the mean over all new green specializations, per green specialization largest relatedness to former specialization counted',
       x = 'Relatedness non-green',
       y = 'Relatedness green',
       size = 'N green patents') 


rm(p1, x_mid, y_mid)

7 Profiling regions

p1 <- tech_rel_dev %>%
  filter(nuts %in% select_region) %>%
  group_by(nuts, nace_group, Y_tag) %>%
  summarise(rel = weight %>% max()) %>%
  ungroup() %>%
  pivot_wider(names_from = Y_tag, values_from = rel, names_prefix = 'Y_', values_fill = 0) %>%
  left_join(tech_dev %>% 
              filter(Y_tag == TRUE, period == '2', rta_bin_delta == 1) %>% 
              select(nuts, nace_group, n_tech_region) %>% 
              count(nuts, nace_group, wt = n_tech_region), 
            by = c('nuts', 'nace_group')) %>%
  mutate(country = nuts %>% str_sub(1,2)) %>%
  left_join(list_nace2 %>%select(nace_group, nace_sec_name), by = 'nace_group')
`summarise()` has grouped output by 'nuts', 'nace_group'. You can override using the `.groups` argument.
#x_mid <- mean(c(max(p1$Y_FALSE, na.rm = TRUE), 
#                min(p1$Y_FALSE, na.rm = TRUE)))

#y_mid <- mean(c(max(p1$Y_TRUE, na.rm = TRUE), 
#                min(p1$Y_TRUE, na.rm = TRUE)))

x_mid <- mean(p1$Y_FALSE, na.rm = TRUE)
y_mid <- mean(p1$Y_TRUE, na.rm = TRUE)

# plotting
p1 %>%
  ggplot(aes(x = Y_FALSE, y = Y_TRUE, size = n, col = nace_sec_name)) +
  geom_point() +
  geom_text_repel(aes(label = nace_group), box.padding = 0.5) +
  geom_vline(xintercept = x_mid, linetype = "dashed", color = 'grey') + 
  geom_hline(yintercept = y_mid, linetype = "dashed", color = 'grey') +
  facet_wrap(vars(nuts)) +
  labs(title = 'New green specialization period 2', 
       subtitle = 'By nuts regions',
       note = 'Relatedness is the mean over all new green specializations, per green specialization largest relatedness to former specialization counted',
       x = 'Relatedness non-green',
       y = 'Relatedness green',
       size = 'N green patents') 


rm(p1, x_mid, y_mid)
path_green_new <- tech_rel_dev %>%
  group_by(nuts, nace_group, Y_tag) %>%
  summarise(rel = weight %>% max()) %>%
  ungroup() %>%
  pivot_wider(names_from = Y_tag, values_from = rel, names_prefix = 'Y_', values_fill = 0) %>%
  left_join(tech_dev %>% 
              filter(Y_tag == TRUE, period == '2', rta_bin_delta == 1) %>% 
              select(nuts, nace_group, n_tech_region) %>% 
              count(nuts, nace_group, wt = n_tech_region), 
            by = c('nuts', 'nace_group')) %>%
  mutate(green_path = case_when( 
    Y_FALSE <= mean(Y_FALSE) & Y_TRUE <= mean(Y_TRUE) ~ 'creation',
    Y_FALSE <= mean(Y_FALSE) & Y_TRUE > mean(Y_TRUE) ~ 'diversification',
    Y_FALSE > mean(Y_FALSE) & Y_TRUE <= mean(Y_TRUE) ~ 'renewal',
    Y_FALSE > mean(Y_FALSE) & Y_TRUE > mean(Y_TRUE) ~ 'renew+div'
    ) ) %>%
  select(-Y_FALSE, - Y_TRUE)
`summarise()` has grouped output by 'nuts', 'nace_group'. You can override using the `.groups` argument.
  • Below a radar plot summing all up.
  • It includes the share of green patents in nace groups folllowing a particular green path (within a nuts region)
  • Color indicates the share of incumbents (+10 years, +50 patents) in the path.
  • Can be used to identify a regions main path and overal profile.
path_green <- tech_dev %>% 
  mutate(green_path = case_when( 
    Y_tag == TRUE & period == '2' & rta_bin == 1 & rta_bin_delta == 0 & rta_delta >= 0.1 ~ 'extension',
    Y_tag == TRUE & period == '2' & rta_bin == 0 & rta_bin_delta == -1 ~ 'extinction'
  )) %>%
  drop_na(green_path) %>%
  select(nuts, nace_group, n_tech_region_delta, green_path) %>%
  rename(n = n_tech_region_delta) %>%
  # add existing green paths
  bind_rows(path_green_new) %>%
  mutate(n = n %>% abs()) %>%
  # add incumbant measures
  left_join(region_techn_incumb %>% filter(period == '2', Y_tag == TRUE) %>% select(nuts, nace_group, share_inc), by = c('nuts', 'nace_group')) %>%
  mutate(n_new = n * (1 - share_inc),
         n_inc = n * share_inc)

8 Geoplotting

  • I also added a first plotting of main green paths
  • Works well, so we can adsd furthr geoplots if necessary.
path_green %>%
  filter(nuts %in% select_region) %>%
  # split by inc and non_incumbents
  pivot_longer(c(n_new, n_inc), names_to = 'applt_type') %>% 
  # Aggregate
  count(nuts, green_path, applt_type, wt = value) %>%
  # Add overall patents andf make share
  left_join(region_RTA %>%filter(period == '2') %>%  count(nuts, wt = n_region, name = 'n_reg'), by = 'nuts') %>%
  mutate(n_share = n / n_reg) %>%
  # plotting
  ggplot() +
  geom_col(aes(x = green_path, y = n_share, fill = applt_type, col = green_path), alpha = 0.8, position= "stack")  + 
  # Lollipop shaft 
  geom_segment( aes(x = green_path, y = 0, xend = green_path, yend = 0.002), linetype = "dashed", color = "gray12") + 
  coord_polar() +
  facet_wrap(vars(nuts), ncol = n_regions) +
  theme(legend.position = 'bottom') +
  labs(title = 'Radar PLot: Regional green paths', 
       subtitle = 'By nuts regions',
       note = 'xxxx',
       x = NULL,
       y = NULL,
       size = 'Share green patents',
       col = 'Green path type',
       fill = 'Applicant type') 

# See: https://ropengov.github.io/giscoR/ 

# Get map of nordics
map_nordic <- gisco_get_nuts(country = c('DNK', 'SWE', 'NOR', 'FIN'), nuts_level = 3, year = '2021')

# filter out Svalbart etc
map_nordic %<>%
  filter(!(NUTS_ID %in% c('NO0B1', 'NO0B2')))

# Group by NUTS by country and convert to lines
country_lines <- map_nordic %>%
  group_by(CNTR_CODE) %>%
  summarise(n = n()) %>%
  ungroup() %>%
  st_cast("MULTILINESTRING")

9 Tech Space changes

map_nordic %>%
  # enter main green path
  left_join(path_green %>% count(nuts, green_path, wt = n) %>% group_by(nuts) %>% slice_max(order_by = n, n = 1, with_ties = FALSE) %>% ungroup(), by = c('NUTS_ID' = 'nuts')) %>%
  # plot
  ggplot() + 
  geom_sf(aes(fill = green_path)) +
  geom_sf(data = country_lines, col = "blue", linewidth = 0.1) + 
  theme_void() +
  labs(title = 'Map: Nordic main green paths', 
       subtitle = 'By nuts regions',
       note = 'xxxx',
       x = NULL,
       y = NULL,
       fill = 'Main green path') 

plot_techspace_dev <- function(g, rta_df, dev_df, region, time = '2', layout_nw = 'nicely'){
  # TODO, C&P function from below once finished
}

TODO: GO ON HERE AND DO BETTER DATAVIZ

# plot_techspace_dev(g = g_tech, rta_df = tech_dev, region = 'DK013', layout_nw = coords_tech) 

10 Endnotes

# TEst for function development
g = g_tech
rta_df = tech_dev
dev_df = tech_rel_dev 
region = 'DK013'
time = '2'
layout_nw = coords_tech

rta_df %<>% 
  filter(nuts == region, period == time, Y_tag == TRUE) %>% 
  select(nace_group, rta, n_tech_region)
  
dev_df %<>%
  filter(nuts == region) %>% 
  group_by(nace_group) %>%
  summarise(prev_nongreen = max(nace_group == related_techn, na.rm = TRUE) %>% as.logical()) %>%
  ungroup() %>%
  replace_na(list(prev_nongreen = FALSE)) %>%
  select(nace_group, prev_nongreen)

g <- g %N>%
  mutate(label = nace_group_name %>% str_trunc(50, side = 'right')) %>%
  left_join(rta_df, by = c("name" = "nace_group")) %N>%
  left_join(dev_df, by = c("name" = "nace_group")) 

g %>%
  ggraph(layout =  coords_tech) + 
  geom_edge_link(aes(width = weight, alpha = weight), colour = "grey") + 
  geom_node_point(aes(colour = rta, shape = prev_nongreen, size = n_tech_region, filter = rta >= 1)) + 
  geom_node_text(aes(label = label, size = n_tech_region, filter = rta >= 1), repel = TRUE) +
  scale_color_gradient2(low = "skyblue", mid = 'yellow', high = "red", midpoint = 1) +
  theme_void() +
  theme(legend.position="bottom") + 
  labs(title = paste("Industry Space:", region, sep = " "),
       subtitle = 'Nodes = NACE 2 Industries. Edges: Relatedness',
       caption = '')

select_regions_green <- tech_dev %>%
  group_by(nuts, period) %>%
  summarise(green =  sum(Y_tag * rta, na.rm = TRUE),
            green_bin =  sum(Y_tag * rta_bin, na.rm = TRUE),
            n_tech_region =  sum(n_tech_region, na.rm = TRUE),
            n_green_region =  sum(Y_tag * n_tech_region, na.rm = TRUE),
            n_green_rta =  sum(Y_tag * n_tech_region * rta_bin, na.rm = TRUE)) %>%
  ungroup() %>%
  filter(n_green_rta >= n_cutoff,
         green_bin >= 1,
         period == '1') %>%
  select(nuts)
tech_spec_dev <- tech_dev %>%
  filter(n_tech_region >= n_cutoff_green) %>%
  group_by(nuts, Y_tag) %>%
  summarise(rta_delta = rta_delta %>% sum(na.rm = TRUE)) %>%
  ungroup() %>%
  pivot_wider(names_from = Y_tag, values_from = rta_delta, values_fill = 0, names_prefix = 'Y_spec_')

—>

LS0tCnRpdGxlOiAnR3JlZW4gUmVnaW9uYWwgUGF0aCBwYXBlcjogRmlyc3QgcmVzdWx0cycKYXV0aG9yOiAiRGFuaWVsIFMuIEhhaW4iCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19mbG9hdDogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgY29kZV9mb2xkaW5nOiBoaWRlCi0tLQoKYGBge3IsIHNldHVwLCBpbmNsdWRlPUZBTFNFfQojIyMgZ2VuZXJhbCBvcHRpb25zClN5cy5zZXRlbnYoTEFORyA9ICJlbiIpCm9wdGlvbnMoInNjaXBlbiIgPSAxMDAsICJkaWdpdHMiID0gNCkgIyBvdmVycmlkZSBSJ3MgdGVuZGVuY3kgdG8gdXNlIHNjaWVudGlmaWMgbm90YXRpb24KCiMjIyBDbGVhbiB3b3Jrc3BhY2UKcm0obGlzdD1scygpKQpncmFwaGljcy5vZmYoKQoKIyMjIExvYWQgcGFja2FnZXMgKG1heWJlIG5lZWQgdG8gYmUgaW5zdGFsbGVkIGZpcnN0KQojIFN0YW5kYXJkCmxpYnJhcnkodGlkeXZlcnNlKSAjIEdlbmVyYWwgRFMgdG9vbGtpdApsaWJyYXJ5KG1hZ3JpdHRyKSAjIEZvciBhZHZhbmNlZCBwaXBpbmcKCiMgRGF0YWJhc2VzCmxpYnJhcnkoREJJKSAjIEdFbmVyYWwgUiBkYXRhYmFzZSBpbnRlcmZhY2UKbGlicmFyeShSUG9zdGdyZXMpICMgUG9zdGdyZVNRTCBpbnRlcmZhY2UgZHJpdmVyIApsaWJyYXJ5KGRicGx5cikgIyBmb3IgZHBseXIgd2l0aCBkYXRhYmFzZXMKCiMgbmV0d29ya3MKbGlicmFyeSh0aWR5Z3JhcGgpCmxpYnJhcnkoZ2dyYXBoKQpsaWJyYXJ5KGdncmVwZWwpCgojIEdFb3Bsb3QKbGlicmFyeShnaXNjb1IpCmxpYnJhcnkoc2YpCmBgYAoKCiMgSW50cm9kdWN0aW9uCgoqIEluIHRoaXMgbm90ZWJvb2ssIHdlIHByZXNlbnQgdGhlIGZpcnN0IHJlc3VsdHMgb2YgYW4gYW5hbHlzaXMgb2YgZ3JlZW4gZGV2ZWxvcG1lbnQgcGF0aHMgb2YgTm9yZGljIHJlZ2lvbnMKKiBJdCBpcyBiYXNlZCBvbiBwYXRlbnQgZGF0YSBmcm9tIDE5OTAtMjAxNSAoUEFUU1RBVCwgQXV0dW1uIDIwMjEgRWRpdGlvbikKKiBBbmFseXNpcyBpcyBkb25lIG9uIGFsbCBOb3JkaWMgTlVUUyAyIHJlZ2lvbnMgKGZyYWN0aW9uYWxpemVkIHBhdGVudCBhbGxvY2F0aW9uIGJ5IGludmVudG9yIGxvY2F0aW9uLCBET0NEQiBmYW1pbHkgbGV2ZWwpCiogSW5kdXN0cmllcyBhcmUgY2FwdHVyZWQgYnkgTkFDRTIgY29kZXMgb2YgcGF0ZW50cyBhY2NvcmRpbmcgdG8gdGhlIE9FQ0QgSVBDLU5BQ0UyIGNvbmNvcmRhbmNlIHRhYmxlLgoqIEdyZWVuIHBhdGVudHMgYXJlIGlkZW50aWZpZWQgdXNpbmcgdGhlIFkwMiB0YWcgaW4gdGhlIENQQyBjbGFzc2lmaWNhdGlvbgoKIyMgUHJlcHJvY2Vzc2luZyAKCmBgYHtyfQojIyBMT0FEIERBVEEKCiMgUmVndWxhciB0YWJsZXMKZGF0YV9hcHBsbiA8LSByZWFkX3JkcygnLi4vdGVtcC9kYXRhX2FwcGxuLnJkcycpCmRhdGFfcGVyc19hcHBsbiAgPC0gcmVhZF9yZHMoJy4uL3RlbXAvZGF0YV9wZXJzX2FwcGxuLnJkcycpCmRhdGFfbmFjZTIgPC0gcmVhZF9yZHMoJy4uL3RlbXAvZGF0YV9uYWNlMi5yZHMnKQoKI2RhdGFfcGVyc29uIDwtIHJlYWRfcmRzKCcuLi90ZW1wL2RhdGFfcGVyc29uLnJkcycpCiNkYXRhX2RvY2RiX2ZhbV9jcGMgPC0gcmVhZF9yZHMoJy4uL3RlbXAvZGF0YV9kb2NkYl9mYW1fY3BjLnJkcycpCgojIFJlZ2lvbmFsIHNwZWNpYWxpemF0aW9uCnJlZ2lvbl9SVEEgPC0gcmVhZF9yZHMoJy4uL3RlbXAvcmVnaW9uX1JUQS5yZHMnKSAlPiUgCiAgbXV0YXRlKGNvdW50cnkgPSBudXRzICU+JSBzdHJfc3ViKDEsMiksCiAgICAgICAgIG51dHNfcGVyaW9kID0gcGFzdGUobnV0cywgJ1AnLCBwZXJpb2QpKSAKCnJlZ2lvbl90ZWNoIDwtIHJlYWRfcmRzKCcuLi90ZW1wL3JlZ2lvbl90ZWNoLnJkcycpICU+JSAKICBtdXRhdGUoY291bnRyeSA9IG51dHMgJT4lIHN0cl9zdWIoMSwyKSwKICAgICAgICAgbnV0c19wZXJpb2QgPSBwYXN0ZShudXRzLCAnUCcsIHBlcmlvZCkpIAoKIyBUZWNobm9sb2d5IHNwYWNlCmdfdGVjaCA8LSByZWFkX3JkcygnLi4vdGVtcC9nX3RlY2gucmRzJykKCiMgTGlzdHMKbGlzdF9uYWNlMiA8LSByZWFkX3JkcygnLi4vdGVtcC9saXN0X25hY2UyLnJkcycpCgojIEFwcGxpY2FudHMKcmVnaW9uX2FwcGx0X2FwcGxuIDwtIHJlYWRfcmRzKCcuLi90ZW1wL3RibF9yZWdpb25fYXBwbHRfYXBwbG4ucmRzJykgJT4lIHNlbGVjdCgtYXBwbHRfc2VxX25yLCAtaW52dF9zZXFfbnIpCnJlZ2lvbl9hcHBsdCA8LSByZWFkX3JkcygnLi4vdGVtcC90YmxfcmVnaW9uX2FwcGx0LnJkcycpCmBgYAoKYGBge3J9CiMjIERlZmluaW5nIHBhcmFtZXRlcnMKbl9jdXRvZmYgPSA1MApuX2N1dG9mZl9ncmVlbiA9IDI1CmBgYAoKYGBge3J9CiMjIFNFTEVDVCBGT0NVUyBSRUdJT05TCnJlZ19pbiA9ICcnICMgYygnU0UyMzInLCAnTk8wNDMnLCAnREswMTInKQpuX3JlZ2lvbnMgPSA1CgojIFJlc3RyaWN0IHRvIHRvcCBOIHJlZ2lvbnMKc2VsZWN0X3JlZ2lvbiA8LSByZWdpb25fdGVjaCAlPiUKICBncm91cF9ieShjb3VudHJ5LCBudXRzKSAlPiUKICBzdW1tYXJpc2UobiA9IHN1bSh3ZWlnaHRfZnJhYywgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgbl9ZID0gc3VtKHdlaWdodF9mcmFjICogWV90YWcsIG5hLnJtID0gVFJVRSkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBncm91cF9ieShjb3VudHJ5KSAlPiUKICBhcnJhbmdlKG51dHMsIGRlc2Mobl9ZKSkgJT4lCiAgbXV0YXRlKGluZGV4ID0gMTpuKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBmaWx0ZXIoaW5kZXggPD0gbl9yZWdpb25zIHwgbnV0cyAlaW4lIHJlZ19pbikgJT4lCiAgZGlzdGluY3QobnV0cykgJT4lCiAgcHVsbChudXRzKQoKcm0ocmVnX2luKQpgYGAKCmBgYHtyfQojIENyZWF0ZWRhdGFmcmFtZSB3aXRoIHRlY2hub2xvZ3kgcmVsYXRlZG5lc3MgZWRnZWxpc3QKdGVjaF9yZWwgPC0gZ190ZWNoICVFPiUKICBtdXRhdGUoZnJvbV9uYWNlID0gLk4oKSRuYW1lW2Zyb21dLAogICAgICAgICB0b19uYWNlID0gLk4oKSRuYW1lW3RvXSkgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgbXV0YXRlKGZyb20gPSBmcm9tX25hY2UgJT4lIGFzLmNoYXJhY3RlcigpLAogICAgICAgICB0byA9IHRvX25hY2UgJT4lIGFzLmNoYXJhY3RlcigpKSAlPiUKICBhcnJhbmdlKGZyb20sIHRvKSAlPiUKICBzZWxlY3QoZnJvbSwgdG8sIHdlaWdodCkKCnRlY2hfcmVsICU8PiUKICAjIEFkZCBvcHBvc2l0ZSBkaXJlY3Rpb24KICBiaW5kX3Jvd3ModGVjaF9yZWwgJT4lIAogICAgICAgICAgICAgIHJlbmFtZShmcm9tX25ldyA9IHRvLCB0b19uZXcgPSBmcm9tKSAlPiUgCiAgICAgICAgICAgICAgcmVuYW1lKGZyb20gPSBmcm9tX25ldywgdG8gPSB0b19uZXcpICU+JQogICAgICAgICAgICAgIHJlbG9jYXRlKGZyb20sIHRvKSkgJT4lCiAgIyBBZGQgc2VsZiBsb29wcwogIGJpbmRfcm93cyh0ZWNoX3JlbCAlPiUKICAgICAgICAgICAgICBkaXN0aW5jdChmcm9tKSAlPiUKICAgICAgICAgICAgICBtdXRhdGUodG8gPSBmcm9tLAogICAgICAgICAgICAgICAgICAgICB3ZWlnaHQgPSAxKSkgJT4lCiAgZGlzdGluY3QoZnJvbSwgdG8sIC5rZWVwX2FsbCA9IFRSVUUpCmBgYAoKCmBgYHtyfQojIFN1bW1hcml6ZSBSZWdpb25zCnJlZ2lvbl9SVEFfYWdnIDwtIHJlZ2lvbl9SVEEgJT4lCiAgZ3JvdXBfYnkoY291bnRyeSwgbnV0cywgcGVyaW9kLCBudXRzX3BlcmlvZCwgWV90YWcpICU+JQogIHN1bW1hcmlzZShuX3NwZWMgPSBydGFfYmluICU+JSBzdW0obmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgbl9zcGVjX2NvdW50ID0gKG5fdGVjaF9yZWdpb24gKiBydGFfYmluKSAlPiUgc3VtKG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIEhISSA9IHN1bSgobl90ZWNoX3JlZ2lvbi9zdW0obl90ZWNoX3JlZ2lvbikgKiAxMDApXjIpICkgJT4lCiAgdW5ncm91cCgpIApgYGAKCmBgYHtyfQojIERhdGFmcmFtZSB3aXRoIHJlZ2lvbnMgYW5kIHRlY2hub2xvZ3kgZmllbGRzCnRlY2hfZGV2IDwtIHJlZ2lvbl9SVEEgJT4lCiAgc2VsZWN0KGNvdW50cnksIHBlcmlvZCwgbnV0cywgbnV0c19wZXJpb2QsIG5hY2VfZ3JvdXAsIFlfdGFnLCBuX3RlY2hfcmVnaW9uLCBydGEsIHJ0YV9iaW4pICU+JQogIGFycmFuZ2UoY291bnRyeSwgbnV0cywgbmFjZV9ncm91cCwgWV90YWcsIHBlcmlvZCkgJT4lCiAgZ3JvdXBfYnkoY291bnRyeSwgbnV0cywgbmFjZV9ncm91cCwgWV90YWcpICU+JQogIG11dGF0ZShuX3RlY2hfcmVnaW9uX2xhZyA9IGxhZyhuX3RlY2hfcmVnaW9uLCAxKSwKICAgICAgICAgbl90ZWNoX3JlZ2lvbl9kZWx0YSA9IG5fdGVjaF9yZWdpb24gLSBuX3RlY2hfcmVnaW9uX2xhZywKICAgICAgICAgcGN0X3RlY2hfcmVnaW9uX2RlbHRhID0gKG5fdGVjaF9yZWdpb24gLSBuX3RlY2hfcmVnaW9uX2xhZykgLyAoIG5fdGVjaF9yZWdpb25fbGFnICsgMSksCiAgICAgICAgIHJ0YV9sYWcgPSBsYWcocnRhLCAxKSwKICAgICAgICAgcnRhX2RlbHRhID0gcnRhIC0gcnRhX2xhZywKICAgICAgICAgcnRhX2Jpbl9sYWcgPSBsYWcocnRhX2JpbiwgMSksCiAgICAgICAgIHJ0YV9iaW5fZGVsdGEgPSBydGFfYmluIC0gcnRhX2Jpbl9sYWcpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBhcnJhbmdlKGNvdW50cnksIG51dHMsIG5hY2VfZ3JvdXAsIFlfdGFnLCBwZXJpb2QpIApgYGAKCiMgUGF0ZW50IGFwcGxpY2F0aW9uIGRldmVsb3BtZW50CgoqIEluIHRoZSBmb2xsb3dpbmcsIGEgYnJpZWYgZGVzY3JpcHRpdmUgYW5hbHlzaXMgb2YgdGhlIGRldmVsb3BtZW50IG9mIGdyZWVuIGFuZCBub24tZ3JlZW4gcGF0ZW50IGFwcGxpY2F0aW9uIGluIHRoZSBOb3JkaWNzCiogSW4gYWRkaXRpb24sIGEgYnJlYWNrZG93biBvZiBncmVlbiBwYXRlbnRzIGJ5IHRvcCBncmVlbiBwYXRlbnRpbmcgcmVhZ2lvbnMKCmBgYHtyfQpkYXRhX2FwcGxuICU+JQogIGNvdW50KGFwcGxuX2ZpbGluZ195ZWFyLCBZX3RhZykgJT4lCiAgZ2dwbG90KGFlcyh4ID0gYXBwbG5fZmlsaW5nX3llYXIsIHkgPSBuLCBjb2wgPSBZX3RhZykpICsgCiAgZ2VvbV9saW5lKGtleV9nbHlwaCA9ICJ0aW1lc2VyaWVzIikgKwogIGxhYnModGl0bGUgPSAnUGF0ZW50IGFwcGxpY2F0aW9uczogRGV2ZWxvcG1lbnQnLAogICAgICAgc3VidGl0bGUgPSAnQWxsIE5vcmRpYyBjb250cmllcywgYnkgWSB0YWcnLAogICAgICAgeCA9ICdZZWFyJywKICAgICAgIHkgPSAnTnVtYmVyIGFwcGxpY2F0aW9ucycsCiAgICAgICBjb2wgPSAnR3JlZW4nKQpgYGAKCmBgYHtyfQpkYXRhX3BlcnNfYXBwbG4gJT4lCiAgZmlsdGVyKG51dHMgJWluJSBzZWxlY3RfcmVnaW9uKSAlPiUKICBjb3VudChhcHBsbl9maWxpbmdfeWVhciwgbnV0cywgWV90YWcsIHd0ID0gd2VpZ2h0X2ZyYWMpICU+JQogIGdncGxvdChhZXMoeCA9IGFwcGxuX2ZpbGluZ195ZWFyLCB5ID0gbiwgY29sID0gbnV0cykpICsgCiAgZ2VvbV9saW5lKGtleV9nbHlwaCA9ICJ0aW1lc2VyaWVzIikgKwogIGZhY2V0X3dyYXAodmFycyhZX3RhZyksIHNjYWxlcyA9ICdmcmVlJykgKwogIGxhYnModGl0bGUgPSAnUGF0ZW50IGFwcGxpY2F0aW9uczogRGV2ZWxvcG1lbnQnLAogICAgICAgc3VidGl0bGUgPSAnQWxsIE5vcmRpYyBjb250cmllcycsCiAgICAgICB4ID0gJ1llYXInLAogICAgICAgeSA9ICdOdW1iZXIgYXBwbGljYXRpb25zLCBieSByZWdpb24gYW5kIFkgdGFnJywKICAgICAgIGNvbCA9ICdOdXRzMycpCmBgYAoKIyBBcHBsaWNhbnRzCgoqIEFwcGxpY2FudHMgb2YgcGF0ZW50cyBmaWxlZCBieSBpbnZlbnRvcnMgaW4gdGhlIE5vcmRpY3MKKiBUaGF0IGNhbiBiZSBkb21lc3RpYyBvciBmb3JlaWduIGFwcGxpY2FudHMKCmBgYHtyfQoKcmVnaW9uX2FwcGx0X2FwcGxuICU8PiUKICBncm91cF9ieShhcHBsbl9pZCkgJT4lCiAgbXV0YXRlKG5fZnJhYyA9IDEgLyBuKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBsZWZ0X2pvaW4ocmVnaW9uX2FwcGx0ICU+JSBzZWxlY3QocGVyc29uX2lkLCBoYW5faWQsIGhhbl9uYW1lLCBwZXJzb25fY3RyeV9jb2RlLCBudXRzKSwgYnkgPSAncGVyc29uX2lkJykgJT4lCiAgbGVmdF9qb2luKGRhdGFfYXBwbG4gJT4lIHNlbGVjdChhcHBsbl9pZCwgZG9jZGJfZmFtaWx5X2lkLCBhcHBsbl9maWxpbmdfeWVhciwgcGVyaW9kLCBZX3RhZyksIGJ5ID0gJ2FwcGxuX2lkJykgJT4lCiAgbGVmdF9qb2luKGRhdGFfbmFjZTIgJT4lIHNlbGVjdChhcHBsbl9pZCwgbmFjZV9ncm91cCkgJT4lIGdyb3VwX2J5KGFwcGxuX2lkKSAlPiUgbXV0YXRlKG5hY2Vfc2hhcmUgPSAxIC8gbigpKSAlPiUgdW5ncm91cCgpICU+JSBuZXN0KG5hY2UgPSBjKG5hY2VfZ3JvdXAsIG5hY2Vfc2hhcmUpKSwgYnkgPSAnYXBwbG5faWQnKSAlPiUKICBkcm9wX25hKCkKYGBgCgoKYGBge3J9CiMgTGlzdCBtYWluIGFwcGxpY2FudHMKYXBwbHRfc3RhdHMgPC0gcmVnaW9uX2FwcGx0X2FwcGxuICU+JQogIGdyb3VwX2J5KGhhbl9pZCwgaGFuX25hbWUsIHBlcnNvbl9jdHJ5X2NvZGUsIG51dHMpICU+JQogIHN1bW1hcmlzZSgKICAgIG5fcGF0ID0gc3VtKG5fZnJhYyksCiAgICBuX1kgPSBzdW0obl9mcmFjICogWV90YWcpLAogICAgZmlyc3RfcGF0ID0gbWluKGFwcGxuX2ZpbGluZ195ZWFyKQogICAgKSAlPiUKICBtdXRhdGUoc2hhcmVfWSA9IG5fWSAvIG5fcGF0LAogICAgICAgICBhZ2UgPSAyMDE2IC0gZmlyc3RfcGF0LAogICAgICAgICBpbmN1bWJhbnQgPSBhZ2UgPj0gMTAgJiBuX3BhdCA+PSBuX2N1dG9mZikgJT4lCiAgdW5ncm91cCgpICU+JQogIGFycmFuZ2UoZGVzYyhuX3BhdCkpCmBgYAoKYGBge3J9CmFwcGx0X3N0YXRzICU+JSBoZWFkKDIwMCkKYGBgCgpgYGB7cn0KYXBwbHRfc3RhdHMgJT4lIGFycmFuZ2UoZGVzYyhuX1kpKSAlPiUgaGVhZCgxMDApCmBgYAoKYGBge3J9CiMgU2hhcmUgb2YgaW5jdW1iYW50cyBieSB0ZWNobm9sb2d5CnJlZ2lvbl90ZWNobl9pbmN1bWIgPC0gcmVnaW9uX2FwcGx0X2FwcGxuICU+JSAKICBsZWZ0X2pvaW4oYXBwbHRfc3RhdHMgJT4lIHNlbGVjdChoYW5faWQsIGluY3VtYmFudCksIGJ5ID0gJ2hhbl9pZCcpICU+JQogIHVubmVzdChuYWNlKSAlPiUKICBtdXRhdGUobl93ZWlnaHQgPSBuX2ZyYWMgKiBuYWNlX3NoYXJlKSAlPiUKICBncm91cF9ieShudXRzLCBuYWNlX2dyb3VwLCBwZXJpb2QsIFlfdGFnKSAlPiUKICBzdW1tYXJpc2UobiA9IHN1bShuX3dlaWdodCksCiAgICAgICAgICAgIG5faW5jID0gc3VtKG5fd2VpZ2h0ICogaW5jdW1iYW50KSkgJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShzaGFyZV9pbmMgPSBuX2luYyAvIG4pCmBgYAoKCiMgVGVjaG5vbG9neSBzcGFjZSBnZW5lcmFsCgoqIFdlIGNhbGN1bGF0ZSB0aGUgcmVsYXRlZG5lc3Mgb2YgaW5kdXN0cmllcyBieSBjby1vY2N1cmVuY2UgcGF0dGVybiBmb2xsb3dpbmcgSGlkYWxnbyAmIEhhdXNtYW5uICgyMDA3KQoqIFJldmVhbGVkIHRlY2hub2xvZ2ljYWwgYWR2YW50YWdlIChSVEEpIElzIHNlcHBlcmF0ZWRseSBjYWxjdWxhdGVkIGZvciBZLXRhZyBhbmQgbm9uLVktdGFnIHBhdGVudHMuCgpgYGB7cn0Kc2V0LnNlZWQoMTMzNykKY29vcmRzX3RlY2ggPC0gZ190ZWNoICU+JSBpZ3JhcGg6OmxheW91dC5mcnVjaHRlcm1hbi5yZWluZ29sZCgpICU+JSBhc190aWJibGUoKQpjb2xuYW1lcyhjb29yZHNfdGVjaCkgPC0gYygieCIsICJ5IikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PSAxMH0KZ190ZWNoICVOPiUKICBtdXRhdGUobmFjZV9ncm91cF9uYW1lID0gbmFjZV9ncm91cF9uYW1lICU+JSBzdHJfdHJ1bmMoNTAsIHNpZGUgPSAncmlnaHQnKSkgJT4lCiAgZ2dyYXBoKGxheW91dCA9ICBjb29yZHNfdGVjaCkgKyAKICBnZW9tX2VkZ2VfbGluayhhZXMod2lkdGggPSB3ZWlnaHQsIGFscGhhID0gd2VpZ2h0KSwgY29sb3VyID0gImdyZXkiKSArIAogIGdlb21fbm9kZV9wb2ludChhZXMoY29sb3VyID0gbmFjZV9zZWNfbmFtZSwgc2l6ZSA9IGRncikpICsgCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFjZV9ncm91cF9uYW1lLCBzaXplID0gZGdyLCBmaWx0ZXIgPSBwZXJjZW50X3JhbmsoZGdyKSA+PSAwLjc1ICksIHJlcGVsID0gVFJVRSkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSArIAogIGxhYnModGl0bGUgPSAnSW5kdXN0cnkgU3BhY2UgKGFsbCBOb3JkaWNzKScsCiAgICAgICBzdWJ0aXRsZSA9ICdOb2RlcyA9IE5BQ0UgMiBJbmR1c3RyaWVzLiBFZGdlczogUmVsYXRlZG5lc3MnKQpgYGAKCiMgUmVnaW9uYWwgc3BlY2lhbGl6YXRpb24gKFJUQSkgZGV2ZWxvcG1lbnQKCiogQ29tcGFyaXNvbiBvZiBzcGVjaWFsaXphdGlvbiBwcm92aWRlcyBpbiBwZXJpb2QgMSBhbmQgMgoKYGBge3J9CnAxIDwtIHJlZ2lvbl9SVEFfYWdnICAlPiUKICBmaWx0ZXIobnV0cyAlaW4lIHNlbGVjdF9yZWdpb24pICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBZX3RhZywgdmFsdWVzX2Zyb20gPSBjKG5fc3BlYywgbl9zcGVjX2NvdW50LCBISEkpLCB2YWx1ZXNfZmlsbCA9IDAsIG5hbWVzX3ByZWZpeCA9ICdZX3RhZ18nKSAKCnAyIDwtIHAxICU+JSAKICBzZWxlY3QocGVyaW9kLCBudXRzLCBuX3NwZWNfWV90YWdfRkFMU0UsIG5fc3BlY19ZX3RhZ19UUlVFKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gcGVyaW9kLCB2YWx1ZXNfZnJvbSA9IGMobl9zcGVjX1lfdGFnX0ZBTFNFLCBuX3NwZWNfWV90YWdfVFJVRSkpCmBgYAoKYGBge3IsIGZpZy53aWR0aD0gNy41LCBmaWcuaGVpZ2h0PTcuNX0KcDEgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbl9zcGVjX1lfdGFnX0ZBTFNFLCB5ID0gbl9zcGVjX1lfdGFnX1RSVUUpKSArCiAgZ2VvbV9zZWdtZW50KGRhdGEgPSBwMiwgCiAgICAgICAgICAgICAgIGFlcyh4ID0gbl9zcGVjX1lfdGFnX0ZBTFNFXzEsCiAgICAgICAgICAgICAgICAgICB5ID0gbl9zcGVjX1lfdGFnX1RSVUVfMSwKICAgICAgICAgICAgICAgICAgIHhlbmQgPSBuX3NwZWNfWV90YWdfRkFMU0VfMiwKICAgICAgICAgICAgICAgICAgIHllbmQgPSBuX3NwZWNfWV90YWdfVFJVRV8yLAogICAgICAgICAgICAgICAgICAgc2l6ZSA9IDAuNzUpLAogICAgICAgICAgICAgICBhbHBoYSA9IDAuMTUsCiAgICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjUsICJjbSIpLCB0eXBlID0gImNsb3NlZCIpLAogICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IG5fc3BlY19jb3VudF9ZX3RhZ19UUlVFLCBjb2wgPSBISElfWV90YWdfVFJVRSkpICsKICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsID0gbnV0cyksIGJveC5wYWRkaW5nID0gMC41LCBtYXgub3ZlcmxhcHMgPSBJbmYpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIobG93ID0gInNreWJsdWUiLCBtaWQgPSAneWVsbG93JywgaGlnaCA9ICJyZWQiLCBtaWRwb2ludCA9IDEpICsKICBzY2FsZV9zaXplKHJhbmdlID0gYygyLCAxMCkpICsgCiAgbGFicyh0aXRsZSA9ICdEZXZlbG9wbWVudCBvZiBuZXcgcmVnaW9uYWwgc3BlY2lhbGl6YXRpb25zJywgCiAgICAgICBzdWJ0aXRsZSA9ICdCeSBudW1iZXIgb2YgZ3JlZW4gYW5kIG5vbiBncmVlbiBzcGVjaWFsaXphdGlvbnMgaW4gcGVyaW9kIDEgYW5kIDInLAogICAgICAgbm90ZSA9ICcnLAogICAgICAgeCA9ICdOIG5vbi1ncmVlbiBzcGVjaWFsaXphdGlvbnMnLAogICAgICAgeSA9ICdOIGdyZWVuIHNwZWNpYWxpemF0aW9ucycsCiAgICAgICBzaXplID0gJ04gZ3JlZW4gcGF0ZW50cycsCiAgICAgICBjb2wgPSAnSEhJIGdyZWVuIHBhdGVudHMnKSAKCnJtKHAxLCBwMikKYGBgCgoKIyBBbmFseXNpcyBmb3IgZXhpc3RpbmcgZ3JlZW4gcGF0aHM6CgpgYGB7cn0KdGVjaF9yZWxfZGV2IDwtIHRlY2hfcmVsICU+JSAKICBzZWxlY3QoZnJvbSwgdG8sIHdlaWdodCkgJT4lCiAgbGVmdF9qb2luKHRlY2hfZGV2ICU+JSBkaXN0aW5jdChuYWNlX2dyb3VwLCBudXRzKSwgYnkgPSBjKCdmcm9tJyA9ICduYWNlX2dyb3VwJykpICU+JQogICMgZmlsdGVyIGZvciBydGEgaW4gcGVyaW9kIDEKICBpbm5lcl9qb2luKHRlY2hfZGV2ICU+JSBmaWx0ZXIocGVyaW9kID09ICcxJywgcnRhX2JpbiA9PSAxKSAlPiUgc2VsZWN0KG5hY2VfZ3JvdXAsIG51dHMsIFlfdGFnKSwgYnkgPSBjKCd0bycgPSAnbmFjZV9ncm91cCcsICdudXRzJykpICU+JQogICMgZmlsdGVyIGZvciBuZXcgZ3JlZW4gc3BlY2lhbGl6YXRpb24gaW4gcGVyaW9kIDIKICBzZW1pX2pvaW4odGVjaF9kZXYgJT4lIGZpbHRlcihwZXJpb2QgPT0gJzInLCBydGFfYmluID09IDEsIHJ0YV9iaW5fZGVsdGEgPT0gMSwgWV90YWcgPT0gVFJVRSksIGJ5ID0gYygnZnJvbScgPSAnbmFjZV9ncm91cCcsICdudXRzJykpICU+JQogIHJlbmFtZShuYWNlX2dyb3VwID0gZnJvbSwgcmVsYXRlZF90ZWNobiA9IHRvKSAKYGBgCgpgYGB7ciwgZmlnLndpZHRoPSA3LjUsIGZpZy5oZWlnaHQ9Ny41fQpwMSA8LSB0ZWNoX3JlbF9kZXYgJT4lCiAgZ3JvdXBfYnkobnV0cywgbmFjZV9ncm91cCwgWV90YWcpICU+JQogIHN1bW1hcmlzZShyZWxfbWF4ID0gd2VpZ2h0ICU+JSBtYXgoKSwKICAgICAgICAgICAgcmVsX3N1bSA9IHdlaWdodCAlPiUgc3VtKCksCiAgICAgICAgICAgIHJlbF9tZWFuID0gd2VpZ2h0ICU+JSBtZWFuKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICAjCiAgZ3JvdXBfYnkobnV0cywgWV90YWcpICU+JQogIHN1bW1hcmlzZShyZWwgPSByZWxfbWF4ICU+JSBtZWFuKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICAjCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IFlfdGFnLCB2YWx1ZXNfZnJvbSA9IHJlbCwgbmFtZXNfcHJlZml4ID0gJ1lfJywgdmFsdWVzX2ZpbGwgPSAwKSAlPiUKICBsZWZ0X2pvaW4odGVjaF9kZXYgJT4lIGZpbHRlcihZX3RhZyA9PSBUUlVFLCBwZXJpb2QgPT0gJzInLCBydGFfYmluID09IDEpICU+JSBzZWxlY3QobnV0cyAsIG5fdGVjaF9yZWdpb24pICU+JSBjb3VudChudXRzLCB3dCA9IG5fdGVjaF9yZWdpb24pLCBieSA9IGMoJ251dHMnKSkgJT4lCiAgbXV0YXRlKGNvdW50cnkgPSBudXRzICU+JSBzdHJfc3ViKDEsMikpIAoKeF9taWQgPC0gbWVhbihwMSRZX0ZBTFNFLCBuYS5ybSA9IFRSVUUpCnlfbWlkIDwtIG1lYW4ocDEkWV9UUlVFLCBuYS5ybSA9IFRSVUUpCgpwMSAlPiUKICBmaWx0ZXIoMC41IDw9IHBlcmNlbnRfcmFuayhuKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gWV9GQUxTRSwgeSA9IFlfVFJVRSwgc2l6ZSA9IG4pKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0geF9taWQsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gJ2dyZXknKSArIAogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IHlfbWlkLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICdncmV5JykgKwogIGdlb21fcG9pbnQoYWVzKGNvbCA9IGNvdW50cnkpKSArCiAgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IG51dHMpLCBib3gucGFkZGluZyA9IDAuNSwgbWF4Lm92ZXJsYXBzID0gSW5mKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSArIAogICAgbGFicyh0aXRsZSA9ICdOZXcgZ3JlZW4gc3BlY2lhbGl6YXRpb24gcGVyaW9kIDInLCAKICAgICAgIHN1YnRpdGxlID0gJ0J5IG51dHMgcmVnaW9ucycsCiAgICAgICBub3RlID0gJ1JlbGF0ZWRuZXNzIGlzIHRoZSBtZWFuIG92ZXIgYWxsIG5ldyBncmVlbiBzcGVjaWFsaXphdGlvbnMsIHBlciBncmVlbiBzcGVjaWFsaXphdGlvbiBsYXJnZXN0IHJlbGF0ZWRuZXNzIHRvIGZvcm1lciBzcGVjaWFsaXphdGlvbiBjb3VudGVkJywKICAgICAgIHggPSAnUmVsYXRlZG5lc3Mgbm9uLWdyZWVuJywKICAgICAgIHkgPSAnUmVsYXRlZG5lc3MgZ3JlZW4nLAogICAgICAgc2l6ZSA9ICdOIGdyZWVuIHBhdGVudHMnKSAKCnJtKHAxLCB4X21pZCwgeV9taWQpCmBgYAoKYGBge3IsIGZpZy53aWR0aD0gMTAsIGZpZy5oZWlnaHQ9MTB9CnAxIDwtIHRlY2hfcmVsX2RldiAlPiUKICBmaWx0ZXIobnV0cyAlaW4lIHNlbGVjdF9yZWdpb24pICU+JQogIGdyb3VwX2J5KG51dHMsIG5hY2VfZ3JvdXAsIFlfdGFnKSAlPiUKICBzdW1tYXJpc2UocmVsID0gd2VpZ2h0ICU+JSBtYXgoKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBZX3RhZywgdmFsdWVzX2Zyb20gPSByZWwsIG5hbWVzX3ByZWZpeCA9ICdZXycsIHZhbHVlc19maWxsID0gMCkgJT4lCiAgbGVmdF9qb2luKHRlY2hfZGV2ICU+JSAKICAgICAgICAgICAgICBmaWx0ZXIoWV90YWcgPT0gVFJVRSwgcGVyaW9kID09ICcyJywgcnRhX2Jpbl9kZWx0YSA9PSAxKSAlPiUgCiAgICAgICAgICAgICAgc2VsZWN0KG51dHMsIG5hY2VfZ3JvdXAsIG5fdGVjaF9yZWdpb24pICU+JSAKICAgICAgICAgICAgICBjb3VudChudXRzLCBuYWNlX2dyb3VwLCB3dCA9IG5fdGVjaF9yZWdpb24pLCAKICAgICAgICAgICAgYnkgPSBjKCdudXRzJywgJ25hY2VfZ3JvdXAnKSkgJT4lCiAgbXV0YXRlKGNvdW50cnkgPSBudXRzICU+JSBzdHJfc3ViKDEsMikpICU+JQogIGxlZnRfam9pbihsaXN0X25hY2UyICU+JXNlbGVjdChuYWNlX2dyb3VwLCBuYWNlX3NlY19uYW1lKSwgYnkgPSAnbmFjZV9ncm91cCcpCgojeF9taWQgPC0gbWVhbihjKG1heChwMSRZX0ZBTFNFLCBuYS5ybSA9IFRSVUUpLCAKIyAgICAgICAgICAgICAgICBtaW4ocDEkWV9GQUxTRSwgbmEucm0gPSBUUlVFKSkpCgojeV9taWQgPC0gbWVhbihjKG1heChwMSRZX1RSVUUsIG5hLnJtID0gVFJVRSksIAojICAgICAgICAgICAgICAgIG1pbihwMSRZX1RSVUUsIG5hLnJtID0gVFJVRSkpKQoKeF9taWQgPC0gbWVhbihwMSRZX0ZBTFNFLCBuYS5ybSA9IFRSVUUpCnlfbWlkIDwtIG1lYW4ocDEkWV9UUlVFLCBuYS5ybSA9IFRSVUUpCgojIHBsb3R0aW5nCnAxICU+JQogIGdncGxvdChhZXMoeCA9IFlfRkFMU0UsIHkgPSBZX1RSVUUsIHNpemUgPSBuLCBjb2wgPSBuYWNlX3NlY19uYW1lKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbCA9IG5hY2VfZ3JvdXApLCBib3gucGFkZGluZyA9IDAuNSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IHhfbWlkLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICdncmV5JykgKyAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSB5X21pZCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAnZ3JleScpICsKICBmYWNldF93cmFwKHZhcnMobnV0cykpICsKICBsYWJzKHRpdGxlID0gJ05ldyBncmVlbiBzcGVjaWFsaXphdGlvbiBwZXJpb2QgMicsIAogICAgICAgc3VidGl0bGUgPSAnQnkgbnV0cyByZWdpb25zJywKICAgICAgIG5vdGUgPSAnUmVsYXRlZG5lc3MgaXMgdGhlIG1lYW4gb3ZlciBhbGwgbmV3IGdyZWVuIHNwZWNpYWxpemF0aW9ucywgcGVyIGdyZWVuIHNwZWNpYWxpemF0aW9uIGxhcmdlc3QgcmVsYXRlZG5lc3MgdG8gZm9ybWVyIHNwZWNpYWxpemF0aW9uIGNvdW50ZWQnLAogICAgICAgeCA9ICdSZWxhdGVkbmVzcyBub24tZ3JlZW4nLAogICAgICAgeSA9ICdSZWxhdGVkbmVzcyBncmVlbicsCiAgICAgICBzaXplID0gJ04gZ3JlZW4gcGF0ZW50cycpIAoKcm0ocDEsIHhfbWlkLCB5X21pZCkKYGBgCgoKIyBQcm9maWxpbmcgcmVnaW9ucwoKYGBge3J9CnBhdGhfZ3JlZW5fbmV3IDwtIHRlY2hfcmVsX2RldiAlPiUKICBncm91cF9ieShudXRzLCBuYWNlX2dyb3VwLCBZX3RhZykgJT4lCiAgc3VtbWFyaXNlKHJlbCA9IHdlaWdodCAlPiUgbWF4KCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gWV90YWcsIHZhbHVlc19mcm9tID0gcmVsLCBuYW1lc19wcmVmaXggPSAnWV8nLCB2YWx1ZXNfZmlsbCA9IDApICU+JQogIGxlZnRfam9pbih0ZWNoX2RldiAlPiUgCiAgICAgICAgICAgICAgZmlsdGVyKFlfdGFnID09IFRSVUUsIHBlcmlvZCA9PSAnMicsIHJ0YV9iaW5fZGVsdGEgPT0gMSkgJT4lIAogICAgICAgICAgICAgIHNlbGVjdChudXRzLCBuYWNlX2dyb3VwLCBuX3RlY2hfcmVnaW9uKSAlPiUgCiAgICAgICAgICAgICAgY291bnQobnV0cywgbmFjZV9ncm91cCwgd3QgPSBuX3RlY2hfcmVnaW9uKSwgCiAgICAgICAgICAgIGJ5ID0gYygnbnV0cycsICduYWNlX2dyb3VwJykpICU+JQogIG11dGF0ZShncmVlbl9wYXRoID0gY2FzZV93aGVuKCAKICAgIFlfRkFMU0UgPD0gbWVhbihZX0ZBTFNFKSAmIFlfVFJVRSA8PSBtZWFuKFlfVFJVRSkgfiAnY3JlYXRpb24nLAogICAgWV9GQUxTRSA8PSBtZWFuKFlfRkFMU0UpICYgWV9UUlVFID4gbWVhbihZX1RSVUUpIH4gJ2RpdmVyc2lmaWNhdGlvbicsCiAgICBZX0ZBTFNFID4gbWVhbihZX0ZBTFNFKSAmIFlfVFJVRSA8PSBtZWFuKFlfVFJVRSkgfiAncmVuZXdhbCcsCiAgICBZX0ZBTFNFID4gbWVhbihZX0ZBTFNFKSAmIFlfVFJVRSA+IG1lYW4oWV9UUlVFKSB+ICdyZW5ldytkaXYnCiAgICApICkgJT4lCiAgc2VsZWN0KC1ZX0ZBTFNFLCAtIFlfVFJVRSkKYGBgCgpgYGB7cn0KcGF0aF9ncmVlbiA8LSB0ZWNoX2RldiAlPiUgCiAgbXV0YXRlKGdyZWVuX3BhdGggPSBjYXNlX3doZW4oIAogICAgWV90YWcgPT0gVFJVRSAmIHBlcmlvZCA9PSAnMicgJiBydGFfYmluID09IDEgJiBydGFfYmluX2RlbHRhID09IDAgJiBydGFfZGVsdGEgPj0gMC4xIH4gJ2V4dGVuc2lvbicsCiAgICBZX3RhZyA9PSBUUlVFICYgcGVyaW9kID09ICcyJyAmIHJ0YV9iaW4gPT0gMCAmIHJ0YV9iaW5fZGVsdGEgPT0gLTEgfiAnZXh0aW5jdGlvbicKICApKSAlPiUKICBkcm9wX25hKGdyZWVuX3BhdGgpICU+JQogIHNlbGVjdChudXRzLCBuYWNlX2dyb3VwLCBuX3RlY2hfcmVnaW9uX2RlbHRhLCBncmVlbl9wYXRoKSAlPiUKICByZW5hbWUobiA9IG5fdGVjaF9yZWdpb25fZGVsdGEpICU+JQogICMgYWRkIGV4aXN0aW5nIGdyZWVuIHBhdGhzCiAgYmluZF9yb3dzKHBhdGhfZ3JlZW5fbmV3KSAlPiUKICBtdXRhdGUobiA9IG4gJT4lIGFicygpKSAlPiUKICAjIGFkZCBpbmN1bWJhbnQgbWVhc3VyZXMKICBsZWZ0X2pvaW4ocmVnaW9uX3RlY2huX2luY3VtYiAlPiUgZmlsdGVyKHBlcmlvZCA9PSAnMicsIFlfdGFnID09IFRSVUUpICU+JSBzZWxlY3QobnV0cywgbmFjZV9ncm91cCwgc2hhcmVfaW5jKSwgYnkgPSBjKCdudXRzJywgJ25hY2VfZ3JvdXAnKSkgJT4lCiAgbXV0YXRlKG5fbmV3ID0gbiAqICgxIC0gc2hhcmVfaW5jKSwKICAgICAgICAgbl9pbmMgPSBuICogc2hhcmVfaW5jKQpgYGAKCiogQmVsb3cgYSByYWRhciBwbG90IHN1bW1pbmcgYWxsIHVwLgoqIEl0IGluY2x1ZGVzIHRoZSBzaGFyZSBvZiBncmVlbiBwYXRlbnRzIGluIG5hY2UgZ3JvdXBzIGZvbGxsb3dpbmcgYSBwYXJ0aWN1bGFyIGdyZWVuIHBhdGggKHdpdGhpbiBhIG51dHMgcmVnaW9uKQoqIENvbG9yIGluZGljYXRlcyB0aGUgc2hhcmUgb2YgaW5jdW1iZW50cyAoKzEwIHllYXJzLCArNTAgcGF0ZW50cykgaW4gdGhlIHBhdGguCiogQ2FuIGJlIHVzZWQgdG8gaWRlbnRpZnkgYSByZWdpb25zIG1haW4gcGF0aCBhbmQgb3ZlcmFsIHByb2ZpbGUuCgpgYGB7ciwgZmlnLndpZHRoPTE1LCBmaWcuaGVpZ2h0PTE1fQpwYXRoX2dyZWVuICU+JQogIGZpbHRlcihudXRzICVpbiUgc2VsZWN0X3JlZ2lvbikgJT4lCiAgIyBzcGxpdCBieSBpbmMgYW5kIG5vbl9pbmN1bWJlbnRzCiAgcGl2b3RfbG9uZ2VyKGMobl9uZXcsIG5faW5jKSwgbmFtZXNfdG8gPSAnYXBwbHRfdHlwZScpICU+JSAKICAjIEFnZ3JlZ2F0ZQogIGNvdW50KG51dHMsIGdyZWVuX3BhdGgsIGFwcGx0X3R5cGUsIHd0ID0gdmFsdWUpICU+JQogICMgQWRkIG92ZXJhbGwgcGF0ZW50cyBhbmRmIG1ha2Ugc2hhcmUKICBsZWZ0X2pvaW4ocmVnaW9uX1JUQSAlPiVmaWx0ZXIocGVyaW9kID09ICcyJykgJT4lICBjb3VudChudXRzLCB3dCA9IG5fcmVnaW9uLCBuYW1lID0gJ25fcmVnJyksIGJ5ID0gJ251dHMnKSAlPiUKICBtdXRhdGUobl9zaGFyZSA9IG4gLyBuX3JlZykgJT4lCiAgIyBwbG90dGluZwogIGdncGxvdCgpICsKICBnZW9tX2NvbChhZXMoeCA9IGdyZWVuX3BhdGgsIHkgPSBuX3NoYXJlLCBmaWxsID0gYXBwbHRfdHlwZSwgY29sID0gZ3JlZW5fcGF0aCksIGFscGhhID0gMC44LCBwb3NpdGlvbj0gInN0YWNrIikgICsgCiAgIyBMb2xsaXBvcCBzaGFmdCAKICBnZW9tX3NlZ21lbnQoIGFlcyh4ID0gZ3JlZW5fcGF0aCwgeSA9IDAsIHhlbmQgPSBncmVlbl9wYXRoLCB5ZW5kID0gMC4wMDIpLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJncmF5MTIiKSArIAogIGNvb3JkX3BvbGFyKCkgKwogIGZhY2V0X3dyYXAodmFycyhudXRzKSwgbmNvbCA9IG5fcmVnaW9ucykgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nKSArCiAgbGFicyh0aXRsZSA9ICdSYWRhciBQTG90OiBSZWdpb25hbCBncmVlbiBwYXRocycsIAogICAgICAgc3VidGl0bGUgPSAnQnkgbnV0cyByZWdpb25zJywKICAgICAgIG5vdGUgPSAneHh4eCcsCiAgICAgICB4ID0gTlVMTCwKICAgICAgIHkgPSBOVUxMLAogICAgICAgc2l6ZSA9ICdTaGFyZSBncmVlbiBwYXRlbnRzJywKICAgICAgIGNvbCA9ICdHcmVlbiBwYXRoIHR5cGUnLAogICAgICAgZmlsbCA9ICdBcHBsaWNhbnQgdHlwZScpIApgYGAKCgoKIyBHZW9wbG90dGluZwoKKiBJIGFsc28gYWRkZWQgYSBmaXJzdCBwbG90dGluZyBvZiBtYWluIGdyZWVuIHBhdGhzCiogV29ya3Mgd2VsbCwgc28gd2UgY2FuIGFkc2QgZnVydGhyIGdlb3Bsb3RzIGlmIG5lY2Vzc2FyeS4KCmBgYHtyfQojIFNlZTogaHR0cHM6Ly9yb3Blbmdvdi5naXRodWIuaW8vZ2lzY29SLyAKCiMgR2V0IG1hcCBvZiBub3JkaWNzCm1hcF9ub3JkaWMgPC0gZ2lzY29fZ2V0X251dHMoY291bnRyeSA9IGMoJ0ROSycsICdTV0UnLCAnTk9SJywgJ0ZJTicpLCBudXRzX2xldmVsID0gMywgeWVhciA9ICcyMDIxJykKCiMgZmlsdGVyIG91dCBTdmFsYmFydCBldGMKbWFwX25vcmRpYyAlPD4lCiAgZmlsdGVyKCEoTlVUU19JRCAlaW4lIGMoJ05PMEIxJywgJ05PMEIyJykpKQoKIyBHcm91cCBieSBOVVRTIGJ5IGNvdW50cnkgYW5kIGNvbnZlcnQgdG8gbGluZXMKY291bnRyeV9saW5lcyA8LSBtYXBfbm9yZGljICU+JQogIGdyb3VwX2J5KENOVFJfQ09ERSkgJT4lCiAgc3VtbWFyaXNlKG4gPSBuKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzdF9jYXN0KCJNVUxUSUxJTkVTVFJJTkciKQpgYGAKCmBgYHtyfQptYXBfbm9yZGljICU+JQogICMgZW50ZXIgbWFpbiBncmVlbiBwYXRoCiAgbGVmdF9qb2luKHBhdGhfZ3JlZW4gJT4lIGNvdW50KG51dHMsIGdyZWVuX3BhdGgsIHd0ID0gbikgJT4lIGdyb3VwX2J5KG51dHMpICU+JSBzbGljZV9tYXgob3JkZXJfYnkgPSBuLCBuID0gMSwgd2l0aF90aWVzID0gRkFMU0UpICU+JSB1bmdyb3VwKCksIGJ5ID0gYygnTlVUU19JRCcgPSAnbnV0cycpKSAlPiUKICAjIHBsb3QKICBnZ3Bsb3QoKSArIAogIGdlb21fc2YoYWVzKGZpbGwgPSBncmVlbl9wYXRoKSkgKwogIGdlb21fc2YoZGF0YSA9IGNvdW50cnlfbGluZXMsIGNvbCA9ICJibHVlIiwgbGluZXdpZHRoID0gMC4xKSArIAogIHRoZW1lX3ZvaWQoKSArCiAgbGFicyh0aXRsZSA9ICdNYXA6IE5vcmRpYyBtYWluIGdyZWVuIHBhdGhzJywgCiAgICAgICBzdWJ0aXRsZSA9ICdCeSBudXRzIHJlZ2lvbnMnLAogICAgICAgbm90ZSA9ICd4eHh4JywKICAgICAgIHggPSBOVUxMLAogICAgICAgeSA9IE5VTEwsCiAgICAgICBmaWxsID0gJ01haW4gZ3JlZW4gcGF0aCcpIApgYGAKCiMgVGVjaCBTcGFjZSBjaGFuZ2VzCgpgYGB7cn0KcGxvdF90ZWNoc3BhY2VfZGV2IDwtIGZ1bmN0aW9uKGcsIHJ0YV9kZiwgZGV2X2RmLCByZWdpb24sIHRpbWUgPSAnMicsIGxheW91dF9udyA9ICduaWNlbHknKXsKICAjIFRPRE8sIEMmUCBmdW5jdGlvbiBmcm9tIGJlbG93IG9uY2UgZmluaXNoZWQKfQpgYGAKCmBgYHtyfQojIHBsb3RfdGVjaHNwYWNlX2RldihnID0gZ190ZWNoLCBydGFfZGYgPSB0ZWNoX2RldiwgcmVnaW9uID0gJ0RLMDEzJywgbGF5b3V0X253ID0gY29vcmRzX3RlY2gpIApgYGAKCgpUT0RPOiBHTyBPTiBIRVJFIEFORCBETyBCRVRURVIgREFUQVZJWgoKYGBge3J9CiMgVEVzdCBmb3IgZnVuY3Rpb24gZGV2ZWxvcG1lbnQKZyA9IGdfdGVjaApydGFfZGYgPSB0ZWNoX2RldgpkZXZfZGYgPSB0ZWNoX3JlbF9kZXYgCnJlZ2lvbiA9ICdESzAxMycKdGltZSA9ICcyJwpsYXlvdXRfbncgPSBjb29yZHNfdGVjaAoKcnRhX2RmICU8PiUgCiAgZmlsdGVyKG51dHMgPT0gcmVnaW9uLCBwZXJpb2QgPT0gdGltZSwgWV90YWcgPT0gVFJVRSkgJT4lIAogIHNlbGVjdChuYWNlX2dyb3VwLCBydGEsIG5fdGVjaF9yZWdpb24pCiAgCmRldl9kZiAlPD4lCiAgZmlsdGVyKG51dHMgPT0gcmVnaW9uKSAlPiUgCiAgZ3JvdXBfYnkobmFjZV9ncm91cCkgJT4lCiAgc3VtbWFyaXNlKHByZXZfbm9uZ3JlZW4gPSBtYXgobmFjZV9ncm91cCA9PSByZWxhdGVkX3RlY2huLCBuYS5ybSA9IFRSVUUpICU+JSBhcy5sb2dpY2FsKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUKICByZXBsYWNlX25hKGxpc3QocHJldl9ub25ncmVlbiA9IEZBTFNFKSkgJT4lCiAgc2VsZWN0KG5hY2VfZ3JvdXAsIHByZXZfbm9uZ3JlZW4pCgpnIDwtIGcgJU4+JQogIG11dGF0ZShsYWJlbCA9IG5hY2VfZ3JvdXBfbmFtZSAlPiUgc3RyX3RydW5jKDUwLCBzaWRlID0gJ3JpZ2h0JykpICU+JQogIGxlZnRfam9pbihydGFfZGYsIGJ5ID0gYygibmFtZSIgPSAibmFjZV9ncm91cCIpKSAlTj4lCiAgbGVmdF9qb2luKGRldl9kZiwgYnkgPSBjKCJuYW1lIiA9ICJuYWNlX2dyb3VwIikpIAoKZyAlPiUKICBnZ3JhcGgobGF5b3V0ID0gIGNvb3Jkc190ZWNoKSArIAogIGdlb21fZWRnZV9saW5rKGFlcyh3aWR0aCA9IHdlaWdodCwgYWxwaGEgPSB3ZWlnaHQpLCBjb2xvdXIgPSAiZ3JleSIpICsgCiAgZ2VvbV9ub2RlX3BvaW50KGFlcyhjb2xvdXIgPSBydGEsIHNoYXBlID0gcHJldl9ub25ncmVlbiwgc2l6ZSA9IG5fdGVjaF9yZWdpb24sIGZpbHRlciA9IHJ0YSA+PSAxKSkgKyAKICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBsYWJlbCwgc2l6ZSA9IG5fdGVjaF9yZWdpb24sIGZpbHRlciA9IHJ0YSA+PSAxKSwgcmVwZWwgPSBUUlVFKSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKGxvdyA9ICJza3libHVlIiwgbWlkID0gJ3llbGxvdycsIGhpZ2ggPSAicmVkIiwgbWlkcG9pbnQgPSAxKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpICsgCiAgbGFicyh0aXRsZSA9IHBhc3RlKCJJbmR1c3RyeSBTcGFjZToiLCByZWdpb24sIHNlcCA9ICIgIiksCiAgICAgICBzdWJ0aXRsZSA9ICdOb2RlcyA9IE5BQ0UgMiBJbmR1c3RyaWVzLiBFZGdlczogUmVsYXRlZG5lc3MnLAogICAgICAgY2FwdGlvbiA9ICcnKQpgYGAKCgoKCgoKIyBFbmRub3RlcwoKYGBge3J9CnNlc3Npb25JbmZvKCkKYGBgCgoKPCEtLS0KCkRST1BQRUQgRk9SIE5PVwoKYGBge3J9CnNlbGVjdF9yZWdpb25zX2dyZWVuIDwtIHRlY2hfZGV2ICU+JQogIGdyb3VwX2J5KG51dHMsIHBlcmlvZCkgJT4lCiAgc3VtbWFyaXNlKGdyZWVuID0gIHN1bShZX3RhZyAqIHJ0YSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgZ3JlZW5fYmluID0gIHN1bShZX3RhZyAqIHJ0YV9iaW4sIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIG5fdGVjaF9yZWdpb24gPSAgc3VtKG5fdGVjaF9yZWdpb24sIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIG5fZ3JlZW5fcmVnaW9uID0gIHN1bShZX3RhZyAqIG5fdGVjaF9yZWdpb24sIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIG5fZ3JlZW5fcnRhID0gIHN1bShZX3RhZyAqIG5fdGVjaF9yZWdpb24gKiBydGFfYmluLCBuYS5ybSA9IFRSVUUpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZmlsdGVyKG5fZ3JlZW5fcnRhID49IG5fY3V0b2ZmLAogICAgICAgICBncmVlbl9iaW4gPj0gMSwKICAgICAgICAgcGVyaW9kID09ICcxJykgJT4lCiAgc2VsZWN0KG51dHMpCmBgYAoKYGBge3J9CnRlY2hfc3BlY19kZXYgPC0gdGVjaF9kZXYgJT4lCiAgZmlsdGVyKG5fdGVjaF9yZWdpb24gPj0gbl9jdXRvZmZfZ3JlZW4pICU+JQogIGdyb3VwX2J5KG51dHMsIFlfdGFnKSAlPiUKICBzdW1tYXJpc2UocnRhX2RlbHRhID0gcnRhX2RlbHRhICU+JSBzdW0obmEucm0gPSBUUlVFKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSBZX3RhZywgdmFsdWVzX2Zyb20gPSBydGFfZGVsdGEsIHZhbHVlc19maWxsID0gMCwgbmFtZXNfcHJlZml4ID0gJ1lfc3BlY18nKQpgYGAKCi0tLT4=